using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using Prota.Unity;
using UnityEngine.Rendering;
using UnityEditor;
using UnityEngine.Rendering.Universal;

namespace Prota.Unity
{
    
    // 集成渲染贴图, 代替 Camera 渲染挂在这个节点里面的物体, 并且可以显示出来.
    // 支持迭代渲染, 可以用来做特殊效果.
    [RequireComponent(typeof(RectTransform))]
    [ExecuteAlways]
    public class SurfaceRenderer : MonoBehaviour, IComparable<SurfaceRenderer>
    {
        public string renderTag = "";
        public int priority = 0;
        public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
        
        public RenderTexture renderTexture;
        
        public bool shouldClear = true;
        [ShowWhen("shouldClear")] public Color clearColor = Color.clear;
        
        public float zNear = -1000;
        public float zFar = 1000;
        public float pixelPerUnit = 16;
        
        public bool preview = true;
        
        public Renderer[] renderers = Array.Empty<Renderer>();
        
        // ====================================================================================================
        // ====================================================================================================
        
        [NonSerialized] RenderTexture handledRenderTexture;
        [EditorButton] public bool fetchRenderers = false;
        
        // ====================================================================================================
        // ====================================================================================================
        
        
        void OnValidate()
        {
            if(zNear >= zFar) Debug.LogError("zNear should be less than zFar.", this);
            EnterRecord();
        }
        
        void Awake()
        {
            EnterRecord();
        }
        
        void OnEnable()
        {
            EnterRecord();
        }
        
        void OnDisable()
        {
            LeaveRecord();
            ClearHandledRenderTexture();
        }
        
        void OnDestroy()
        {
            LeaveRecord();
            ClearHandledRenderTexture();
        }
        
        void ClearHandledRenderTexture()
        {
            if(handledRenderTexture != null)
            {
                DestroyImmediate(handledRenderTexture);
                handledRenderTexture = null;
            }
        }
        
        void Update()
        {
            if(fetchRenderers.SwapSet(false))
            {
                renderers = this.GetComponentsInChildren<Renderer>().ToArray();
                foreach(var rd in renderers) rd.enabled = false;
            }
        }
        
        // ====================================================================================================
        // ====================================================================================================
        
        public void PrepareRenderTexture()
        {
            if(renderTexture != handledRenderTexture && handledRenderTexture != null)
            {
                ClearHandledRenderTexture();
            }
            
            if(!renderTexture)
            {
                handledRenderTexture = renderTexture = new RenderTexture(1, 1, 0, RenderTextureFormat.ARGB32);
                handledRenderTexture.name = "Generated Texture";
            }
        }
        
        public void ResizeRenderTexture()
        {
            var expectedSize = (this.RectTransform().rect.size * pixelPerUnit).RoundToInt();
            if(renderTexture.texelSize == expectedSize) return;
            renderTexture.Resize(expectedSize);
        }
        
        public readonly List<Renderer> rendererList = new();
        public void PrepareRendererList()
        {
            rendererList.Clear();
            var rect = this.RectTransform().WorldRect();
            var thisBounds = new Bounds(rect.center.ToVec3(zNear), rect.size.ToVec3(zFar - zNear));
            
            foreach(var rd in renderers)
                if(rd && rd.bounds.Intersects(thisBounds))
                    rendererList.Add(rd);
            
            if(StandaloneRenderer.all.ContainsKey(renderTag))
                foreach(var srd in StandaloneRenderer.all[renderTag])
                {
                    if(!srd) continue;
                    if(!srd.rd.PassValue(out var rd)) continue;
                    // if(!rd.bounds.Intersects(thisBounds)) continue;
                    rendererList.Add(srd.rd);
                }
        }
        
        
        // ====================================================================================================
        // ====================================================================================================
        
        public int CompareTo(SurfaceRenderer other)
        {
            return this.priority.CompareTo(other.priority);
        }
        
        // ====================================================================================================
        // ====================================================================================================
        
        
        public readonly static List<SurfaceRenderer> all = new();
        
        void EnterRecord()
        {
            if(this.gameObject.IsPrefab()) return;
            all.Remove(this);
            all.Add(this);
            all.Sort();
        }
        
        void LeaveRecord()
        {
            all.Remove(this);
        }
    }
}
